]> git.r.bdr.sh - rbdr/map/blobdiff - Map/Presentation/Base Components/MapTextEditor.swift
Add license notices
[rbdr/map] / Map / Presentation / Base Components / MapTextEditor.swift
index f3838a663aa83d63dc22bf688326b93176a704a5..31da790c41cbe3b9c009e99364c1d928a335be52 100644 (file)
@@ -1,9 +1,25 @@
+/*
+ Copyright (C) 2024 Rubén Beltrán del Río
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see https://map.tranquil.systems.
+ */
 import Cocoa
 import SwiftUI
 
 class MapTextEditorController: NSViewController {
 
-  @Binding var text: String
+  @Binding var document: MapDocument
   let onChange: () -> Void
 
   private let vertexRegex = MapParsingPatterns.vertex
@@ -12,11 +28,12 @@ class MapTextEditorController: NSViewController {
   private let opportunityRegex = MapParsingPatterns.opportunity
   private let noteRegex = MapParsingPatterns.note
   private let stageRegex = MapParsingPatterns.stage
+  private let groupRegex = MapParsingPatterns.group
 
   private let changeDebouncer: Debouncer = Debouncer(seconds: 1)
 
-    init(text: Binding<String>, onChange: @escaping () -> Void) {
-    self._text = text
+  init(document: Binding<MapDocument>, onChange: @escaping () -> Void) {
+    self._document = document
     self.onChange = onChange
     super.init(nibName: nil, bundle: nil)
   }
@@ -31,10 +48,11 @@ class MapTextEditorController: NSViewController {
 
     scrollView.translatesAutoresizingMaskIntoConstraints = false
 
+    textView.backgroundColor = .ui.background
     textView.allowsUndo = true
     textView.delegate = self
     textView.textStorage?.delegate = self
-    textView.string = self.text
+    textView.string = self.document.text
     textView.isEditable = true
     textView.font = .monospacedSystemFont(ofSize: 16.0, weight: .regular)
     self.view = scrollView
@@ -49,14 +67,13 @@ extension MapTextEditorController: NSTextViewDelegate {
 
   func textDidChange(_ obj: Notification) {
     if let textField = obj.object as? NSTextView {
-      self.text = textField.string
-        
-        
-        changeDebouncer.debounce {
-          DispatchQueue.main.async {
-            self.onChange()
-          }
+      self.document.text = textField.string
+
+      changeDebouncer.debounce {
+        DispatchQueue.main.async {
+          self.onChange()
         }
+      }
     }
   }
 
@@ -86,65 +103,91 @@ extension MapTextEditorController: NSTextStorageDelegate {
     var matches = vertexRegex.matches(in: textStorage.string, options: [], range: range)
 
     for match in matches {
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 1))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 3))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 4))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 1))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.number], range: match.range(at: 3))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.option], range: match.range(at: 4))
     }
 
     matches = edgeRegex.matches(in: textStorage.string, options: [], range: range)
 
     for match in matches {
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 1))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 1))
       let arrowRange = match.range(at: 2)
       textStorage.addAttributes(
         [.foregroundColor: NSColor.syntax.symbol],
         range: NSMakeRange(arrowRange.lowerBound - 1, arrowRange.length + 1))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 3))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 3))
     }
 
     matches = opportunityRegex.matches(in: textStorage.string, options: [], range: range)
 
     for match in matches {
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.symbol], range: match.range(at: 3))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 4))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.symbol], range: match.range(at: 3))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.number], range: match.range(at: 4))
     }
 
     matches = blockerRegex.matches(in: textStorage.string, options: [], range: range)
 
     for match in matches {
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
     }
-    
+
     matches = noteRegex.matches(in: textStorage.string, options: [], range: range)
 
     for match in matches {
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 3))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.number], range: match.range(at: 3))
     }
 
     matches = stageRegex.matches(in: textStorage.string, options: [], range: range)
 
     for match in matches {
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
-      textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
+    }
+
+    matches = groupRegex.matches(in: textStorage.string, options: [], range: range)
+
+    for match in matches {
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+      textStorage.addAttributes(
+        [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
     }
   }
 }
 
 struct MapTextEditor: NSViewControllerRepresentable {
 
-  @Binding var text: String
+  @Binding var document: MapDocument
   var onChange: () -> Void = {}
 
   func makeNSViewController(
     context: NSViewControllerRepresentableContext<MapTextEditor>
   ) -> MapTextEditorController {
-    return MapTextEditorController(text: $text, onChange: onChange)
+    return MapTextEditorController(document: $document, onChange: onChange)
   }
 
   func updateNSViewController(